/**
 * 
 */
package com.oauth.facebook.server.service;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;

import com.google.code.facebook.graph.client.oauth.FacebookAccessToken;
import com.google.code.facebook.graph.client.oauth.FacebookOAuthService;
import com.google.code.facebook.graph.client.oauth.FacebookOAuthServiceFactory;
import com.google.code.facebook.graph.model.enumeration.Permission;
import com.oauth.common.server.beans.OAuthAccessToken;
import com.oauth.common.server.beans.OAuthConfigBean;
import com.oauth.common.server.beans.OAuthRequestToken;
import com.oauth.facebook.client.beans.FacebookUser;
import com.oauth.facebook.server.beans.FacebookRequestToken;
import com.oauth.facebook.server.beans.FbUser;
import com.oauth.facebook.server.beans.Result;
import com.oauth.facebook.server.domain.FacebookBean;
import com.oauth.facebook.server.util.BirthdayComparator;
import com.oauth.facebook.server.util.FacebookUtil;
import com.oauth.service.application.global.beans.Birthday;
import com.oauth.service.generic.OAuthService;
import com.oauth.service.generic.beans.OAuthServiceBean;
import com.restfb.Connection;
import com.restfb.DefaultFacebookClient;
import com.restfb.Parameter;
import com.restfb.types.Post;
import com.restfb.types.User;

/**
 * @author asanthan
 * 
 */
public class FacebookServiceImpl implements FacebookService {

	private static final Parameter[] EMPTY_PARAMETER = new Parameter[0];

	private FacebookOAuthService facebookOauthService;

	private OAuthService mOAuthService;
	private OAuthConfigBean mOAuthConfigBean;
	private Set<Permission> permissionSet;

	/**
	 * @param pOAuthService
	 *            the oAuthService to set
	 */
	@Autowired(required = true)
	public void setOAuthService(OAuthService pOAuthService) {
		mOAuthService = pOAuthService;
	}

	/**
	 * @param pOAuthConfigBean
	 *            the oAuthConfigBean to set
	 */
	@Required
	public void setOAuthConfigBean(OAuthConfigBean pOAuthConfigBean) {
		mOAuthConfigBean = pOAuthConfigBean;
	}

	@PostConstruct
	public void initialize() {
		facebookOauthService = FacebookOAuthServiceFactory.getInstance()
				.createFacebookOAuthService(mOAuthConfigBean.getConsumerKey(),
						mOAuthConfigBean.getConsumerSecret());

		permissionSet = new HashSet<Permission>(Arrays.asList(Permission.values()));
	}

	private DefaultFacebookClient getFacebookClient(Long pMemberId) throws Exception {
		OAuthAccessToken accessToken = getAccessTokenFromDB(pMemberId);
		DefaultFacebookClient client = new DefaultFacebookClient(accessToken.getToken());
		return client;
	}

	@Override
	public OAuthAccessToken getAccessTokenFromDB(Long pMemberId) throws Exception {
		OAuthServiceBean token = null;
		token = mOAuthService.getToken(pMemberId, FacebookBean.class);
		if (token != null) {
			return new OAuthAccessToken(token.getAccessToken(), token.getAccessTokenSecret());
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seecom.oauth.facebook.server.service.FacebookService#
	 * getAccessTokenFromRequestToken
	 * (com.oauth.common.server.beans.OAuthRequestToken, java.lang.String)
	 * 
	 * NOTE: We are not using request token from the parameter.
	 */
	@Override
	public OAuthAccessToken getAccessTokenFromRequestToken(OAuthRequestToken pRequestToken,
			String pVerifier) throws Exception {
		FacebookAccessToken accessToken = facebookOauthService.getAccessToken(mOAuthConfigBean
				.getCallBackUrl(), pVerifier);
		// Get access token .
		return new OAuthAccessToken(accessToken.getAccessToken(), accessToken.getAccessToken());
	}

	@Override
	public FacebookRequestToken getRequestToken() throws Exception {

		String authzUrl = facebookOauthService.getAuthorizationUrl(mOAuthConfigBean
				.getCallBackUrl(), permissionSet);
		return new FacebookRequestToken(null, null, authzUrl);
	}

	@Override
	public void persistAccessToken(OAuthAccessToken pAccessToken, Long pMemberId) throws Exception {
		FacebookBean serviceBean = new FacebookBean();
		serviceBean.setAccessToken(pAccessToken.getToken());
		serviceBean.setAccessTokenSecret(pAccessToken.getTokenSecret());
		serviceBean.setMemberId(pMemberId);
		// serviceBean.setTwitterId(twitter.getUserId());
		mOAuthService.persistToken(serviceBean); // persist in db for future
		// use.
	}

	@Override
	public List<FacebookUser> getFriends(Long pMemberId) throws Exception {
		DefaultFacebookClient facebookClient = getFacebookClient(pMemberId);
		Connection<User> connections = facebookClient.fetchConnection("me/friends", User.class,
				Parameter.with("fields", "id, name,picture"));
		return FacebookUtil.getUsers(connections);
	}

	@Override
	public List<Birthday> getUpcomingBirthdays(Long pMemberId, int pBirthdayInterval)
			throws Exception {
		DefaultFacebookClient facebookClient = getFacebookClient(pMemberId);
		List<FbUser> userList = getUserWithUpcomingBirthday(facebookClient, pBirthdayInterval);
		return FacebookUtil.getBirthdays(userList);
	}

	@Override
	public List<FacebookUser> getMessages(Long pMemberId) throws Exception {
		// getLinkedInClient(pMemberId).getp
		return null;
	}

	@Override
	public List<FacebookUser> getUpdates(Long pMemberId) throws Exception {
		DefaultFacebookClient facebookClient = getFacebookClient(pMemberId);
		Connection<Post> myFeed = facebookClient.fetchConnection("me/home", Post.class);
		return FacebookUtil.getUpdates(myFeed);

	}

	private List<FbUser> getUserWithUpcomingBirthday(DefaultFacebookClient pFacebookClient,
			int pBirthdayInterval) throws Exception {
		String fqlQuery = FacebookUtil.getBirthdayFQLQuery(pBirthdayInterval);
		List<FbUser> userList = pFacebookClient.executeQuery(fqlQuery, FbUser.class,
				EMPTY_PARAMETER);
		// SORT userlist.
		Collections.sort(userList, new BirthdayComparator());
		return userList;
	}

	private String getStatus(Long pFacebookUserId, DefaultFacebookClient pFacebookClient)
			throws Exception {
		List<Result> results = pFacebookClient.executeQuery("select message from status where uid="
				+ pFacebookUserId, Result.class);
		if (results != null && !results.isEmpty()) {
			return results.get(0).getMessage();
		}
		return "What's on your mind?";
	}

	@Override
	public FacebookUser getFacebookUser(Long pMemberId) throws Exception {
		DefaultFacebookClient facebookClient = getFacebookClient(pMemberId);
		User user = facebookClient.fetchObject("me", User.class, Parameter.with("fields",
				"id,name,picture"));
		FacebookUser user2 = FacebookUtil.getUser(user);
		user2.setStatus(getStatus(user2.getId(), facebookClient));
		return user2;

	}

	@Override
	public void updateStatus(String pText, Long pMemberId) throws Exception {
		System.out.println("Updating..." + pText);
		DefaultFacebookClient facebookClient = getFacebookClient(pMemberId);
		facebookClient.publish("me/feed", Post.class, Parameter.with("message", pText));
	}
}
